/*
 * @(#)Ruler.java	1.0 Apr 27, 2008
 *
 *	The MIT License
 *
 *	Copyright (c) 2008 Malachi de AElfweald <malachid@gmail.com>
 *
 *	Permission is hereby granted, free of charge, to any person obtaining a copy
 *	of this software and associated documentation files (the "Software"), to deal
 *	in the Software without restriction, including without limitation the rights
 *	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the Software is
 *	furnished to do so, subject to the following conditions:
 *
 *	The above copyright notice and this permission notice shall be included in
 *	all copies or substantial portions of the Software.
 *
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *	THE SOFTWARE.
 */
package org.eoti.swing;

import org.eoti.awt.WebColor;

import javax.swing.*;
import java.awt.*;

public class Ruler
		extends JViewport
{
	public enum Orientation{Horizontal,Vertical}
	public enum Unit
	{
		Inch("in", 0.5),
		Centimeter("cm", 1.0),
		Pixel("px", 50.0);

		Unit(String abbrev, double defaultIncrement)
		{
			this.abbrev = abbrev;
			this.defaultIncrement = defaultIncrement;
		}
		protected String abbrev;
		public String getAbbreviation(){return abbrev;}
		protected double defaultIncrement;
		public double getDefaultIncrement(){return defaultIncrement;}
	}

	protected Orientation orientation;
	protected Unit unit;
	protected double increment;
	protected int thickness;
    protected Color fg,bg;
    protected Font font;

	public Ruler(Orientation orientation, Unit unit, int thickness)
	{
		super();
		setOrientation(orientation);
		setUnits(unit);
		setThickness(thickness);
		setForeground(WebColor.Black);
		setBackground(WebColor.CornSilk);
		setFont(new Font("SansSerif", Font.PLAIN, 10));
	}


	public void setThickness(int thickness){this.thickness = thickness;}
	public int getThickness(){return thickness;}

	public void setForeground(WebColor color){setForeground(color.getColor());}
	public void setForeground(Color color){this.fg = color;}
	public Color getForeground(){return fg;}

	public void setBackground(WebColor color){setBackground(color.getColor());}
	public void setBackground(Color color){this.bg = color;}
	public Color getBackground(){return bg;}

	public void setOrientation(Orientation orientation){this.orientation = orientation;}
	public Orientation getOrientation(){return orientation;}

	public Unit getUnits(){return unit;}
	public void setUnits(Unit unit)
	{
		this.unit = unit;
		setIncrement(unit.getDefaultIncrement());
	}

	public double getIncrement(){return increment;}
	public void setIncrement(double increment)
	{
		this.increment = increment;
		repaint();
	}

	public double getDotsPerUnit(){return getDotsPerUnit(unit);}
	public double getDotsPerUnit(Unit unit)
	{
		switch(unit)
		{
			case Pixel:
				return 1;
			case Inch:
				return Toolkit.getDefaultToolkit().getScreenResolution();
			case Centimeter:
				return getDotsPerUnit(Unit.Inch) / 2.54;
		}
		return 0;
	}

	public int getDotsPerIncrement()
	{
        return (int)(getDotsPerUnit() * increment);
	}

	public void setPreferredSize(ImageIcon icon)
	{
		switch(orientation)
		{
			case Horizontal:
				setPreferredSize(new Dimension(icon.getIconWidth(), thickness));
				break;
			case Vertical:
				setPreferredSize(new Dimension(thickness, icon.getIconHeight()));
				break;
		}
	}

	public JPanel createMatchingCorner()
	{
		JPanel pnl = new JPanel();
		pnl.setBackground(bg);
		pnl.setForeground(fg);
		return pnl;
	}

	public void setFont(Font font){this.font = font;}
	public Font getFont(){return font;}

	public void paintComponent(Graphics g)
	{
		if(unit == null)
			return; // not setup yet

		Rectangle bounds = g.getClipBounds();
		g.setColor(bg);
		g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
		g.setColor(fg);
		g.setFont(font);

		int dotsPerIncrement = getDotsPerIncrement();
		int dotsPerUnit = (int)(getDotsPerUnit());

		int textSize = 0;
		String text = null;
		int start = 0;
		int end = 0;
		int tickLength = 0;

		// determine first and last tick within clipping bounds
        switch(orientation)
		{
			case Horizontal:
				start = ((bounds.x / dotsPerUnit) * dotsPerUnit);
				end = (((bounds.x + bounds.width) / dotsPerUnit) + 1) * dotsPerUnit;
				textSize = (font.getSize() * 2) + 1;
				break;
			case Vertical:
				start = ((bounds.y / dotsPerUnit) * dotsPerUnit);
				end = (((bounds.y + bounds.height) / dotsPerUnit) + 1) * dotsPerUnit;
				textSize = font.getSize() - 1;
				break;
		}

        // If we are at the edge (ie: start=0), then we want "0 px" or "0 cm" or "0 in"
		// draw starting tick and label
		if(start == 0)
		{
			text = String.format("0 %s", unit.getAbbreviation());
			tickLength = 10;
			drawTick(g, start, tickLength);
			switch(orientation)
			{
				case Horizontal:
					g.drawString(text, 2, textSize);
					break;
				case Vertical:
					g.drawString(text, textSize, 10);
					break;
			}
			text = null;
			start = dotsPerIncrement;
		}

		// draw all the ticks and labels
		for(int i=start; i<end; i+=dotsPerIncrement)
		{
			if((i % dotsPerUnit) == 0)
			{
				// we are on an even UNIT, so draw full tick with label
                tickLength = 10;
				text = Integer.toString(i/dotsPerUnit);
			}else{
				// not on even UNIT, so tick but no label
				tickLength = 7;
				text = null;
			}

			drawTick(g, i, tickLength);
			drawText(g, i, text, textSize);
		}
	}

	protected void drawText(Graphics g, int position, String text, int textSize)
	{
		if(text == null) return;
		switch(orientation)
		{
			case Horizontal:
				g.drawString(text, position-3, textSize);
				break;
			case Vertical:
				g.drawString(text, textSize, position+3);
				break;
		}
	}

	protected void drawTick(Graphics g, int position, int tickLength)
	{
		switch(orientation)
		{
			case Horizontal:
				g.drawLine(position, thickness-1, position, thickness-tickLength-1);
				break;
			case Vertical:
				g.drawLine(thickness-1, position, thickness-tickLength-1, position);
				break;
		}
	}
}
